package com.gly091020.GLYCan.block;

import com.gly091020.GLYCan.GLYCanMod;
import com.gly091020.GLYCan.block.entity.CanBlockEntity;
import com.gly091020.GLYCan.util.CanComponent;
import com.gly091020.GLYCan.util.CanItemContainer;
import com.mojang.serialization.MapCodec;
import net.minecraft.advancements.AdvancementHolder;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.NonNullList;
import net.minecraft.core.component.DataComponents;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.ServerAdvancementManager;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.tags.ItemTags;
import net.minecraft.world.Containers;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.ItemInteractionResult;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.DyeItem;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.item.component.ItemContainerContents;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.EntityBlock;
import net.minecraft.world.level.block.HorizontalDirectionalBlock;
import net.minecraft.world.level.block.RenderShape;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition;
import net.minecraft.world.level.block.state.properties.BooleanProperty;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.Shapes;
import net.minecraft.world.phys.shapes.VoxelShape;
import org.jetbrains.annotations.Nullable;

import java.util.Objects;

public class CanBlock extends HorizontalDirectionalBlock implements EntityBlock{
    private static final VoxelShape COLLISION_SHAPE = Shapes.box(4f/16, 0f/16, 4f/16, 12f/16, 13f/16, 12f/16);
    public static final BooleanProperty IS_TETO = BooleanProperty.create("is_teto");
    public static final int NORMAL_COLOR = 0xD3D3D3;
    public CanBlock(Properties properties) {
        super(properties);
        this.registerDefaultState(this.stateDefinition.any().setValue(FACING, Direction.NORTH).setValue(IS_TETO, false));
    }

    @Override
    protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
        builder.add(FACING);
        builder.add(IS_TETO);
    }

    @Override
    protected MapCodec<? extends HorizontalDirectionalBlock> codec() {
        return simpleCodec(CanBlock::new);
    }

    @Override
    public @Nullable BlockEntity newBlockEntity(BlockPos blockPos, BlockState blockState) {
        return new CanBlockEntity(blockPos, blockState);
    }

    @Override
    protected VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
        return COLLISION_SHAPE;
    }

    @Override
    protected VoxelShape getCollisionShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
        return COLLISION_SHAPE;
    }

    @Override
    protected void onRemove(BlockState state, Level level, BlockPos pos, BlockState state1, boolean b) {
        if(state.is(state1.getBlock())){
            super.onRemove(state, level, pos, state1, b);return;
        }
        ItemStack stack = new ItemStack(GLYCanMod.CAN);
        CanItemContainer container = new CanItemContainer(stack);
        if(!(level.getBlockEntity(pos) instanceof CanBlockEntity entity)){
            super.onRemove(state, level, pos, state1, b);
            return;
        }
        container.setItems(entity.getItems());
        stack.set(GLYCanMod.CAN_COMPONENTS.get(), new CanComponent(state.getValue(IS_TETO), entity.color));
        Containers.dropItemStack(level, pos.getX(), pos.getY(), pos.getZ(), stack);
        super.onRemove(state, level, pos, state1, b);
    }

    @Override
    protected ItemInteractionResult useItemOn(ItemStack itemStack, BlockState state, Level level, BlockPos pos, Player player, InteractionHand interactionHand, BlockHitResult result) {
        if(itemStack.is(GLYCanMod.CAN)){return ItemInteractionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION;}
        if(!(level.getBlockEntity(pos) instanceof CanBlockEntity entity)){return ItemInteractionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION;}

        if(itemStack.is(Items.SPONGE)){
            if(entity.color == NORMAL_COLOR){
                return ItemInteractionResult.SKIP_DEFAULT_BLOCK_INTERACTION;
            }
            entity.color = NORMAL_COLOR;
            entity.setChanged();
            level.sendBlockUpdated(pos, state, state, 3);
            level.playLocalSound(pos, SoundEvents.SPONGE_ABSORB, SoundSource.PLAYERS, 1, 1, true);
            return ItemInteractionResult.SUCCESS;
        }

        if(itemStack.getItem() instanceof DyeItem item){
            if(entity.color == item.getDyeColor().getTextureDiffuseColor()){
                return ItemInteractionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION;
            }else if(entity.color == NORMAL_COLOR){
                entity.color = item.getDyeColor().getTextureDiffuseColor();
            }else{
                entity.color = blendColors(entity.color, item.getDyeColor().getTextureDiffuseColor(),
                        0.8f, 0.2f);
            }
            entity.setChanged();
            level.sendBlockUpdated(pos, state, state, 3);
            level.playLocalSound(pos, SoundEvents.DYE_USE, SoundSource.PLAYERS, 1, 1, true);

            itemStack.consume(1, player);
            return ItemInteractionResult.SUCCESS;
        }

        var f = itemStack.getFoodProperties(player);
        if(!itemStack.is(ItemTags.create(ResourceLocation.parse("c:foods"))) &&
                !itemStack.is(ItemTags.create(ResourceLocation.parse("c:drinks"))) &&
                !itemStack.has(DataComponents.FOOD) &&
                !itemStack.has(DataComponents.POTION_CONTENTS) &&
                !itemStack.has(DataComponents.SUSPICIOUS_STEW_EFFECTS)){
            return ItemInteractionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION;
        }

        var i1 = itemStack.copy();
        i1.setCount(1);
        if(!entity.addItems(i1)){return ItemInteractionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION;}

        itemStack.consume(1, player);
        return ItemInteractionResult.SUCCESS;
    }

    @Override
    public void setPlacedBy(Level level, BlockPos pos, BlockState state, @Nullable LivingEntity placer, ItemStack stack) {
        super.setPlacedBy(level, pos, state, placer, stack);
        if(level.getBlockEntity(pos) instanceof CanBlockEntity entity){
            var l = NonNullList.withSize(10, ItemStack.EMPTY);
            stack.getOrDefault(DataComponents.CONTAINER, ItemContainerContents.EMPTY).copyInto(l);
            entity.setItems(l);
        }
        setTeto(level, pos, state, placer, stack);
    }

    public void setTeto(Level level, BlockPos pos, BlockState state, @Nullable LivingEntity placer, ItemStack stack){
        if(level.getBlockEntity(pos) instanceof CanBlockEntity entity && level.getBlockEntity(pos.below()) instanceof CanBlockEntity entity1){
            if(entity.isTomatoCan() && entity1.isTomatoCan()){
                level.setBlock(pos, state.setValue(CanBlock.IS_TETO, true), Block.UPDATE_ALL);
                level.playLocalSound(pos, GLYCanMod.TETO_CAN_SOUND.get(), SoundSource.BLOCKS, 1, 1, true);
                if(placer instanceof ServerPlayer player){
                    grantAdvancement(player, ResourceLocation.parse("gly_can:teto_can"), "teto");
                }
            }
        }
    }

    private static int blendColors(int color1, int color2, float weight1, float weight2) {
        // deepseek
        if (Math.abs(weight1 + weight2 - 1.0f) > 0.0001f) {
            throw new IllegalArgumentException("Weights must sum to 1.0");
        }

        // 提取 ARGB 分量
        int a1 = (color1 >> 24) & 0xFF;
        int r1 = (color1 >> 16) & 0xFF;
        int g1 = (color1 >> 8) & 0xFF;
        int b1 = color1 & 0xFF;

        int a2 = (color2 >> 24) & 0xFF;
        int r2 = (color2 >> 16) & 0xFF;
        int g2 = (color2 >> 8) & 0xFF;
        int b2 = color2 & 0xFF;

        // 计算混合后的分量
        int a = (int) (a1 * weight1 + a2 * weight2);
        int r = (int) (r1 * weight1 + r2 * weight2);
        int g = (int) (g1 * weight1 + g2 * weight2);
        int b = (int) (b1 * weight1 + b2 * weight2);

        // 确保值在 0~255 范围内
        a = Math.max(0, Math.min(255, a));
        r = Math.max(0, Math.min(255, r));
        g = Math.max(0, Math.min(255, g));
        b = Math.max(0, Math.min(255, b));

        // 重新组合为 ARGB int
        return (a << 24) | (r << 16) | (g << 8) | b;
    }

    @Override
    public RenderShape getRenderShape(BlockState state) {
        return RenderShape.MODEL;
    }

    @Override
    protected InteractionResult useWithoutItem(BlockState state, Level level, BlockPos pos, Player player, BlockHitResult hitResult) {
        if(player.isShiftKeyDown() && level.getBlockEntity(pos) instanceof CanBlockEntity entity && !entity.isEmpty()){
            for(int i = entity.getItems().size() - 1;i >= 0;i--){
                var stack = entity.getItems().get(i);
                if(!stack.isEmpty()){
                    var s = stack.finishUsingItem(level, player);
                    if(!player.hasInfiniteMaterials()){
                        player.addItem(s);
                    }
                    entity.removeItem(i, 1);
                    if(!player.level().isClientSide && !Objects.equals(player.getGameProfile().getName(), "test-mock-player")){
                        grantAdvancement((ServerPlayer) player, ResourceLocation.parse("gly_can:eat_can_block"), "eat_block");
                    }
                    return InteractionResult.SUCCESS;
                }
            }
        }
        return super.useWithoutItem(state, level, pos, player, hitResult);
    }

    @Override
    public @Nullable BlockState getStateForPlacement(BlockPlaceContext context) {
        return defaultBlockState().setValue(FACING, context.getHorizontalDirection().getOpposite());
    }

    public void grantAdvancement(ServerPlayer player, ResourceLocation advancementId, String key) {
        ServerAdvancementManager manager = player.server.getAdvancements();
        AdvancementHolder advancement = manager.get(advancementId);

        if (advancement != null) {
            player.getAdvancements().award(advancement, key);
        }
    }
}
